package com.dap.utils;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.Address;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.event.TransportListener;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Collection;
import java.util.Properties;
import java.util.concurrent.LinkedBlockingQueue;

public class EmailSender {
    private static final Logger logger = LoggerFactory.getLogger(EmailSender.class);

    private final static String defaultMailHost = "smtp.qq.com";
    private final static int defaultMailHostPort = 465;
    private final static String defaultMailHostUser = "591593903@qq.com";
    private final static String defaultMailHostPassword = "ldyvmkhtxfcdbbga";

    private String mailHost = defaultMailHost;
    private int mainHostPort = defaultMailHostPort;
    private String mailHostUser = defaultMailHostUser;
    private String mailHostPassword = defaultMailHostPassword;
    public String getMailHost() {
        return mailHost;
    }
    public void setMailHost(String mailHost) {
        this.mailHost = mailHost;
    }
    public int getMainHostPort() {
        return mainHostPort;
    }
    public void setMainHostPort(int mainHostPort) {
        this.mainHostPort = mainHostPort;
    }
    public String getMailHostUser() {
        return mailHostUser;
    }
    public void setMailHostUser(String mailHostUser) {
        this.mailHostUser = mailHostUser;
    }
    public String getMailHostPassword() {
        return mailHostPassword;
    }
    public void setMailHostPassword(String mailHostPassword) {
        this.mailHostPassword = mailHostPassword;
    }



    private Properties generateMailSessionProperties() {
        Properties mailSessionProperties = new Properties();
        mailSessionProperties.put("mail.transport.protocol", "smtp");
        mailSessionProperties.put("mail.smtp.host", mailHost);
        mailSessionProperties.put("mail.smtp.port", mainHostPort);
        mailSessionProperties.put("mail.smtp.auth", "true");
        mailSessionProperties.put("mail.smtp.ssl.enable", "true");
        mailSessionProperties.put("mail.debug", "false");

        // 连接时间限制，单位毫秒
        mailSessionProperties.put("mail.smtp.connectiontimeout", 10000);
        // 邮件接收时间限制，单位毫秒
        mailSessionProperties.put("mail.smtp.timeout", 60000);
        // 邮件发送时间限制，单位毫秒
        mailSessionProperties.put("mail.smtp.writetimeout", 60000);
        return mailSessionProperties;
    }


    /**
     * 创建一封只包含文本的邮件
     */
    private MimeMessage createSimpleMail(Session session, String mailSubject, String mailContent, String mailFrom, Address[] recipients) throws Exception {
        //创建邮件对象
        MimeMessage mimeMessage = new MimeMessage(session);
        //指明邮件的发件人
        mimeMessage.setFrom(new InternetAddress(mailFrom));

        //指明邮件的收件人，现在发件人和收件人是一样的，那就是自己给自己发
        mimeMessage.setRecipients(MimeMessage.RecipientType.TO, recipients);

        //邮件的标题
        mimeMessage.setSubject(mailSubject);
        //邮件的文本内容
        mimeMessage.setContent(mailContent, "text/html;charset=UTF-8");
        //返回创建好的邮件对象
        return mimeMessage;
    }


    private static Address[] generateRecipients(Collection<String> mailList) throws AddressException {
        Address[] recipients = new Address[mailList.size()];

        int i=0;
        for (String notifyEmail : mailList) {
            recipients[i] = new InternetAddress(notifyEmail);
            ++i;
        }

        return recipients;
    }

    /**
     * 同步发送一个只包含文本的简单邮件
     * */
    public void sendSimpleEmailSync(String mailSubject, String mailContent,
            String mailFrom, Collection<String> mailToList) throws Exception {
        sendSimpleEmailSync(null, mailSubject, mailContent, mailFrom, mailToList);
    }
    public void sendSimpleEmailSync(TransportListener transportListener,
            String mailSubject, String mailContent,
            String mailFrom, Collection<String> mailToList) throws Exception {
        //1、创建session
        Session session = Session.getInstance(generateMailSessionProperties());
        session.setDebug(false);

        //2、通过session得到transport对象
        Transport ts = session.getTransport();

        //3、使用邮箱的用户名和密码连上邮件服务器，发送邮件时，发件人需要提交邮箱的用户名和密码给smtp服务器，用户名和密码都通过验证之后才能够正常发送邮件给收件人。
        ts.connect(mailHost, mainHostPort, mailHostUser, mailHostPassword);

        //4、设置监听
        if (null != transportListener) {
            ts.addTransportListener(transportListener);
        }

        //5、创建邮件
        Address[] recipients = generateRecipients(mailToList);
        MimeMessage mimeMessage = createSimpleMail(session, mailSubject, mailContent, mailFrom, recipients);

        //6、发送邮件
        ts.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
        ts.close();
    }



    private static class SendEmailQueueParam {
        public final EmailSender emailSender;
        public final TransportListener transportListener;

        public final String mailSubject;
        public final String mailContent;
        public final String mailFrom;
        public final Collection<String> mailToList;
        public SendEmailQueueParam(EmailSender emailSender, TransportListener transportListener,
                String mailSubject, String mailContent, String mailFrom, Collection<String> mailToList) {
            this.emailSender = emailSender;
            this.transportListener = transportListener;
            this.mailSubject = mailSubject;
            this.mailContent = mailContent;
            this.mailFrom = mailFrom;
            this.mailToList = mailToList;
        }
    }
    private static final LinkedBlockingQueue<SendEmailQueueParam> queue = new LinkedBlockingQueue<>(2048);
    private static void enqueueMessage(EmailSender emailSender, TransportListener transportListener,
            String mailSubject, String mailContent,
            String mailFrom, Collection<String> mailToList) {
        SendEmailQueueParam sendEmailQueueParam = new SendEmailQueueParam(emailSender, transportListener,
                                                                          mailSubject, mailContent, mailFrom, mailToList);
        // offer方法在添加元素时，如果发现队列已满无法添加的话，会直接返回false
        if (!queue.offer(sendEmailQueueParam)) {
            logger.info("enqueue failed, will send later, sendEmailQueueParam={}", JSON.toJSONString(sendEmailQueueParam));
        }
    }
    private static Thread sendEmailThread;
    static {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (isSendThreadRun) {
                    try {
                        // take:若队列为空，发生阻塞，等待有元素
                        SendEmailQueueParam sendEmailQueueParam = queue.take();
                        if (sendEmailQueueParam != null) {
                            sendEmailQueueParam.emailSender.sendSimpleEmailSync(
                                    sendEmailQueueParam.transportListener,
                                    sendEmailQueueParam.mailSubject, sendEmailQueueParam.mailContent,
                                    sendEmailQueueParam.mailFrom, sendEmailQueueParam.mailToList);
                        }
                    } catch (Exception e) {
                        logger.warn("", e);
                    }
                }
            }
        };

        sendEmailThread = new Thread(runnable);
        sendEmailThread.start();
    }
    private static volatile boolean isSendThreadRun = true;
    public static void stopSendEmailThread() {
        isSendThreadRun = false;
        sendEmailThread.interrupt();
    }

    /**
     * 异步发送一个只包含文本的简单邮件
     * */
    public void sendSimpleEmailAsync(String mailSubject, String mailContent,
            String mailFrom, Collection<String> mailToList) {
        sendSimpleEmailAsync(null, mailSubject, mailContent, mailFrom, mailToList);
    }
    public void sendSimpleEmailAsync(TransportListener transportListener,
            String mailSubject, String mailContent,
            String mailFrom, Collection<String> mailToList) {
        enqueueMessage(this, transportListener, mailSubject, mailContent, mailFrom, mailToList);
    }

    
    

    public static void main(String[] args) throws Exception {
        new EmailSender().sendSimpleEmailAsync(
                        "test", "testc2", "591593903@qq.com", Lists.newArrayList("591593903@qq.com"));
        stopSendEmailThread();
    }
}
